package ${package.ServiceImpl};
<#if ES_URIS??>
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.Map;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import javax.annotation.Resource;
import ${package.Dao}.${entity}EsDao;
import ${package.Entity}.${entity}Es;
    <#if ES_STRATEGY == ES_STRATEGY_DOUBLE_WRITE>
import org.springframework.transaction.annotation.Transactional;
    </#if>
</#if>
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.layuiframework.stereotype.exception.ThrowUtils;
import org.layuiframework.stereotype.vo.ResultCode;
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import ${package.Vo}.${table.voName};
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.layuiframework.stereotype.annotation.ImportFromFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * ${table.comment!} 服务实现类
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Service
<#if ES_URIS??>
    <#if ES_STRATEGY == ES_STRATEGY_DOUBLE_WRITE>
@Transactional
    </#if>
</#if>
<#if kotlin>
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {

}
<#else>
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {

<#if ES_URIS??>
    @Resource
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Resource
    ${entity}EsDao ${table.layuiEntityName}EsDao;
</#if>

    @Override
    public PageInfo<${entity}> page${table.entityName}(${table.voName} vo){
        PageHelper.startPage(vo.getPage(), vo.getLimit());
        QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
        <#if table.layuiNameColumn??>
        queryWrapper.like(StringUtils.hasLength(vo.getName()), "${table.layuiNameColumn.name}" , vo.getName());
        </#if>
        <#if table.layuiTimeColumn??>
        if(null != vo.getEndTime()) vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
        queryWrapper.ge(null != vo.getStartTime(), "${table.layuiTimeColumn.name}", vo.getStartTime());
        queryWrapper.le(null != vo.getEndTime(), "${table.layuiTimeColumn.name}", vo.getEndTime());
        queryWrapper.orderByDesc(" ${table.layuiTimeColumn.name} ");
        </#if>
        List<${entity}> dtos = this.list(queryWrapper);
        return new PageInfo(dtos);
    }

    @Override
    public List<${entity}> list${table.entityName}(${table.voName} vo){
<#if table.layuiTimeColumn??>
        if(null != vo.getEndTime()) vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
</#if>
        return this.list(new QueryWrapper<${entity}>()
           <#if table.layuiNameColumn??>
            .like(StringUtils.hasLength(vo.getName()), "${table.layuiNameColumn.name}" , vo.getName())
           </#if>
           <#if table.layuiTimeColumn??>
            .ge(null != vo.getStartTime(), "${table.layuiTimeColumn.name}", vo.getStartTime())
            .le(null != vo.getEndTime(), "${table.layuiTimeColumn.name}", vo.getEndTime())
            .orderByDesc(" ${table.layuiTimeColumn.name} ")
           </#if>
        );
    }

    @ImportFromFile
    @Override
    public List<${entity}> excel${table.entityName}(MultipartFile file, List<${entity}> objects, HttpServletRequest request){
        for (${entity} ${table.layuiEntityName}: objects) {
             <#if table.layuiIdColumn??>
            // TODO 在这里修改实体类的信息
            ${table.layuiEntityName}.set${table.layuiIdColumn.capitalName}(null);
             </#if>
        }
    <#if ES_URIS??>
        <#if ES_STRATEGY == ES_STRATEGY_DOUBLE_WRITE>
        // TODO 这里数据库的录入是在后置事件中进行的,这里不能获取到生成的主键信息。需要在上面主动补充上主键信息
        /**
        if(!objects.isEmpty()){
            <#assign entityEs = entity + 'Es' />
            List<${entityEs}> esList = objects.stream().map(${entity} :: transform).collect(Collectors.toList());
            final int pageSize = 500;
            int total = esList.size();
            for (int i = 0; i < total; i += pageSize) {
                int end = Math.min(i + pageSize, total);
                ${table.layuiEntityName}EsDao.saveAll(esList.subList(i, end));
            }
        }
        **/
        </#if>
    </#if>
        return objects;
    }

    @Override
    public boolean add${table.entityName}(${entity} ${table.layuiEntityName}, HttpServletRequest request){
        // TODO 追加信息，比如从请求对象中将用户信息取出来放入对象中
        // ${table.layuiEntityName}.setCreateuser("");
        // 保存信息,如果失败抛出异常去处理
        ThrowUtils.throwIf(!this.save(${table.layuiEntityName}), ResultCode.NETERROR);
    <#if ES_URIS??>
        <#if ES_STRATEGY == ES_STRATEGY_DOUBLE_WRITE>
        // 数据库与es双写,先写数据库。1.以数据库为准; 2.生成主键id
        ${table.layuiEntityName}EsDao.save(${table.layuiEntityName}.transform());
        </#if>
    </#if>
        return true;
    }

    @Override
    public boolean update${table.entityName}(${entity} ${table.layuiEntityName}){
        // 保存信息,如果失败抛出异常去处理
        ThrowUtils.throwIf(!this.updateById(${table.layuiEntityName}), ResultCode.NETERROR);
    <#if ES_URIS??>
        <#if ES_STRATEGY == ES_STRATEGY_DOUBLE_WRITE>
        // 数据库与es双写,先写数据库。
        ${table.layuiEntityName}EsDao.save(${table.layuiEntityName}.transform());
        </#if>
    </#if>
        return true;
    }

    @Override
    public boolean delete${table.entityName}(${entity} ${table.layuiEntityName}){
        // 保存信息,如果失败抛出异常去处理
        ThrowUtils.throwIf(!this.removeById(${table.layuiEntityName}), ResultCode.NETERROR);
    <#if ES_URIS??>
        <#if ES_STRATEGY == ES_STRATEGY_DOUBLE_WRITE>
        // 数据库与es双写,先写数据库。
        ${table.layuiEntityName}EsDao.delete(${table.layuiEntityName}.transform());
        </#if>
    </#if>
        return true;
    }

    @Override
    public void export${table.entityName}(${table.voName} vo, HttpServletResponse response) throws IOException {
        response.setHeader("content-Type", "application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // TODO 修改excel文件标题
        String title = "测试";
        // TODO 修改excel文件名称
        String filename = java.net.URLEncoder.encode(title, "UTF-8") + ".xlsx";
        // TODO 修改excel文件sheet名称
        String sheetname = "sheet1";
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
        <#if table.layuiNameColumn??>
        queryWrapper.like(StringUtils.hasLength(vo.getName()), "${table.layuiNameColumn.name}" , vo.getName());
        </#if>
        <#if table.layuiTimeColumn??>
        if(null != vo.getEndTime()) vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
        queryWrapper.ge(null != vo.getStartTime(), "${table.layuiTimeColumn.name}", vo.getStartTime());
        queryWrapper.le(null != vo.getEndTime(), "${table.layuiTimeColumn.name}", vo.getEndTime());
        queryWrapper.orderByDesc(" ${table.layuiTimeColumn.name} ");
        </#if>
        List<${entity}> exports = this.list(queryWrapper);
        ServletOutputStream outputStream = response.getOutputStream();
        EasyExcel.write(outputStream, ${entity}.class).head(${entity}.class)
            .sheet(sheetname)
            .useDefaultStyle(true).relativeHeadRowIndex(2).doWrite(exports);
        outputStream.flush();
    }

<#if ES_URIS??>
    @Override
    public PageInfo<${entity}> page${table.entityName}Es(${table.voName} vo){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SortBuilder sortBuilder = SortBuilders.scoreSort();
        if(StringUtils.hasLength(vo.getName()))
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(vo.getName()<#list table.fields as field><#if field.keyFlag><#assign keyField = field /></#if><#if (field.propertyType=="String")><#if (!field.radioColumn && !field.selectColumn)>,"${field.columnName}"</#if></#if></#list>));
    <#if table.updateColumn??>
        if(null != vo.getEndTime()){
            vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
            boolQueryBuilder.must(QueryBuilders.rangeQuery("${table.updateColumn.columnName}").to(vo.getEndTime()));
        }
        if(null != vo.getStartTime())
            boolQueryBuilder.must(QueryBuilders.rangeQuery("${table.updateColumn.columnName}").from(vo.getStartTime()));
        // sortBuilder = SortBuilders.fieldSort("${table.updateColumn.columnName}");
        // sortBuilder.order(SortOrder.DESC);
    </#if>
        PageRequest pageRequest = PageRequest.of(vo.getPage(), vo.getLimit());
<#assign highlightField = 'HighlightBuilder.Field' />
        List<${highlightField}> fields = new ArrayList<>();
    <#list table.fields as field>
        <#if (field.propertyType=="String")>
            <#if (!field.radioColumn && !field.selectColumn)>
        fields.add(new HighlightBuilder.Field("${field.columnName}"));
            </#if>
        </#if>
    </#list>
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withPageable(pageRequest).withSorts(sortBuilder).withHighlightFields(fields).build();
    <#assign entityEs = entity + 'Es' />
        SearchHits<${entityEs}> searchHits = elasticsearchRestTemplate.search(searchQuery, ${entityEs}.class);
        PageInfo<${entity}> page = new PageInfo<>();
        page.setTotal(searchHits.getTotalHits());
        List<${entity}> resourceList = new ArrayList<>();
        if (searchHits.hasSearchHits()) {
    <#assign searchHit = 'SearchHit' />
            List<${searchHit}<${entityEs}>> searchHitList = searchHits.getSearchHits();
            Map<${keyField.propertyType}, List<${searchHit}<${entityEs}>>> searchHitMap = searchHitList.stream().collect(Collectors.groupingBy(searchHit -> searchHit.getContent().get${keyField.capitalName}()));
            List<${keyField.propertyType}> ${table.layuiEntityName}IdList = searchHitList.stream().map(searchHit -> searchHit.getContent().get${keyField.capitalName}()).collect(Collectors.toList());
            // 从数据库中取出更完整的数据
            List<${entity}> ${table.layuiEntityName}List = baseMapper.selectBatchIds(${table.layuiEntityName}IdList);
            if (${table.layuiEntityName}List != null) {
                Map<${keyField.propertyType}, List<${entity}>> id${entity}Map = ${table.layuiEntityName}List.stream().collect(Collectors.groupingBy(${entity} :: get${keyField.capitalName}));
                ${table.layuiEntityName}IdList.forEach(${table.layuiEntityName}Id -> {
                    if (id${entity}Map.containsKey(${table.layuiEntityName}Id)) {
                        ${entity} ${table.layuiEntityName} = id${entity}Map.get(${table.layuiEntityName}Id).get(0);
                        String highlightContent = searchHitMap.get(${table.layuiEntityName}Id).get(0).getHighlightFields().values().stream().map(m -> m.get(0)).collect(Collectors.joining("|"));
                        ${table.layuiEntityName}.setElasticsearchHintcontent(highlightContent);
                        ${table.layuiEntityName}.setElasticsearchScore((double) searchHitMap.get(${table.layuiEntityName}Id).get(0).getScore());
                        resourceList.add(${table.layuiEntityName});
                    } else {
                        // 从 es 清空 db 已物理删除的数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(${table.layuiEntityName}Id), ${entityEs}.class);
                    }
                });
            }
        }
        page.setList(resourceList);
        return page;
    }

</#if>
}
</#if>
